#include "stm32f10x.h"                  // Device header
#include "list.h"

#if 0
#include "bsp_led.h"
#include "bsp_systick.h"
#include "bsp_uart.h"
#include "bsp_sleep.h"

typedef enum {
	EVENT_NONE = 0,
	EVENT_ENTER_SLEEP,
	EVENT_WAKE_UP,
}SleepEventType;

typedef enum {
	STATE_NORMAL = 0,
	STATE_READY_TO_SLEEP,
	STATE_SLEEPING,
}SleepStateType;
#endif

#define HEAP_SIZE					128

uint32_t system_ticks = 0;
uint8_t uart1_tx_buffer[HEAP_SIZE] = {0};
uint8_t uart2_tx_buffer[HEAP_SIZE] = {0};

void NVIC_Configuration(void);
void bsp_systick_init(void);
void bsp_led_init(void);
void bsp_uart1_init(void);
void bsp_uart2_init(void);


void EnterSleepMode_EXTI(void);
void ExitSleepMode_EXIT(void);
void ExitSleepMode_Sysclk(void);
void bsp_system_save(void);
void start_uart1_dma(void);
void start_uart2_dma(void);
void put_dma_buffer(char *s, uint16_t len);
void uart1_putc(char c);
int uart1_puts(char *s);


void mymemset(void *s, char val, uint16_t len)
{
	char *c_s = s;
	for(uint16_t i = len; i>0; i--) {
		*c_s = 0;
		c_s++;
	}

}

void mymemcpy(void *dst, void *src, uint16_t len)
{
	char *c_dst = dst, *c_src = src;
	while(len != 0) {
		len--;
		*c_dst = *c_src;
		c_dst++;
		c_src++;
	}
}


/*
两种思路
一种是DMA有自己的一块RAM空间，即在使用DMA时，需要调用类似malloc的函数获取固定大小的ram空间，
然后，通过类似memcpy的函数，将数据存入该ram空间中，这片ram空间的使用和释放归DMA管理。
我把这种方式叫做获取，写入的方式——获取DMA的可写入空间，用户向该空间写入数据。
简单来说就是固定DMA的传输地址。

另一种是用户管理RAM空间，它与第一种方式有所差异，操作起来更像是写入，获取的方式——
用户向自己定义的空间写入数据，DMA获取需要发送的数据地址以及数据的大小。
简单来说就是不固定DMA的地址

用户需要标记当前写入位置，当前读取位置，当前传输位置。ram空间的使用和释放归用户

结合DMA的使用特性，起始地址+字/半字/字节数量。注意字节对齐。
指定发送的数据结束时，产生中断。

由此，在中断产生之前，不可以对RAM空间进行整理，允许写入。


这样写有什么用呢？？？？通过区分两种方式，我们可以更好的理解内存空间的分配和释放。

比如我们有数个类似于UART的外设或者module，那么何时为外设分配内存空间，何时为外设释放内存空间就十分讲究了。
如果外设1，每1000ms占用一次256Bytes的空间，我们只需在它需要时分配，而外设1的这部分空间将在分配10ms后使用完毕
(发送完毕)，那么我们释放的256Bytes空间将会有990ms，可供其它外设使用。

类似的，module或许每10ms需要使用一次256Bytes的空间，每次使用2ms。那么这256Bytes的空间就有8ms可以供别的module使用！！！
*/
/*第一种*/
/*定义需要的参数*/
uint32_t DMA_CH4_Tx_Addr = 0;
uint16_t DMA_CH4_Tx_WritePos = 0;
uint16_t DMA_CH4_Tx_ReadPos = 0;
void *mymalloc4(uint16_t NeededSize)
{
	uint8_t* return_addr = NULL;
	/*获取当前写入位置*/
	/*1.判断剩余空间*/
	if(NeededSize> (HEAP_SIZE-DMA_CH4_Tx_WritePos)) {
		return NULL;
	}
	/*2.记录当前写入位置*/
	return_addr = &uart1_tx_buffer[DMA_CH4_Tx_WritePos];
	/*计算新的写入位置*/
	/*1.更新写入位置*/
	DMA_CH4_Tx_WritePos += NeededSize;
	/*2.计算剩余空间*/
	/*DMA_Tx_RemainSize -= NeededSize;*/
	
	return (void* )return_addr;
}

void start_uart1_dma(void)
{
	if((DMA1_Channel4->CCR & DMA_CCR1_EN) == DISABLE) {
		/*DMA空闲*/
		if(DMA_CH4_Tx_WritePos > 0) {
			DMA_CH4_Tx_ReadPos = DMA_CH4_Tx_WritePos;
			/*有数据可发*/
			DMA1_Channel4->CMAR = (uint32_t)&uart1_tx_buffer[0];//指定传输的地址，CMAR是32位寄存器，
			DMA_SetCurrDataCounter(DMA1_Channel4, DMA_CH4_Tx_ReadPos);
			DMA_ITConfig(DMA1_Channel4, DMA_IT_TC, ENABLE);
			DMA_Cmd(DMA1_Channel4, ENABLE);
		}
		else {
			/*无数据可发*/
			DMA_CH4_Tx_ReadPos = 0;
		}
	}
	else {
		/*DMA 正在传输数据*/
	}
}

/*空间由dma回收*/
/*
* 这里由void 转为char 存在字节对齐的问题，不同架构可能有所差异
* 差异带来的问题，可能会导致一些“异常”
*/
void dma_ch4_free(void *s)
{
	char *c_s = s;
//	mymemset(c_s, 0, DMA_Tx_ReadPos);
	/*整理RAM空间*/
	DMA_CH4_Tx_WritePos -= DMA_CH4_Tx_ReadPos;
	/*根据传输位置和以发送的数量，释放空间*/
	DMA_CH4_Tx_ReadPos = 0;
}

uint32_t DMA_CH7_Tx_Addr = 0;
uint16_t DMA_CH7_Tx_WritePos = 0;
uint16_t DMA_CH7_Tx_ReadPos = 0;
void *mymalloc7(uint16_t NeededSize)
{
	uint8_t* return_addr = NULL;
	/*获取当前写入位置*/
	/*1.判断剩余空间*/
	if(NeededSize> (HEAP_SIZE-DMA_CH7_Tx_WritePos)) {
		return NULL;
	}
	/*2.记录当前写入位置*/
	return_addr = &uart2_tx_buffer[DMA_CH7_Tx_WritePos];
	/*计算新的写入位置*/
	/*1.更新写入位置*/
	DMA_CH7_Tx_WritePos += NeededSize;
	/*2.计算剩余空间*/
	/*DMA_Tx_RemainSize -= NeededSize;*/
	
	return (void* )return_addr;
}
void start_uart2_dma(void)
{
	if((DMA1_Channel7->CCR & DMA_CCR1_EN) == DISABLE) {
		/*DMA空闲*/
		if(DMA_CH7_Tx_WritePos > 0) {
			DMA_CH7_Tx_ReadPos = DMA_CH7_Tx_WritePos;
			/*有数据可发*/
			DMA1_Channel7->CMAR = (uint32_t)&uart2_tx_buffer[0];//指定传输的地址，CMAR是32位寄存器，
			DMA_SetCurrDataCounter(DMA1_Channel7, DMA_CH7_Tx_ReadPos);
			DMA_ITConfig(DMA1_Channel7, DMA_IT_TC, ENABLE);
			DMA_Cmd(DMA1_Channel7, ENABLE);
		}
		else {
			/*无数据可发*/
			DMA_CH7_Tx_ReadPos = 0;
		}
	}
	else {
		/*DMA 正在传输数据*/
	}
}
/*空间由dma回收*/
/*
* 这里由void 转为char 存在字节对齐的问题，不同架构可能有所差异
* 差异带来的问题，可能会导致一些“异常”
*/
void dma_ch7_free(void *s)
{
	char *c_s = s;
//	mymemset(c_s, 0, DMA_Tx_ReadPos);
	/*整理RAM空间*/
	DMA_CH7_Tx_WritePos -= DMA_CH7_Tx_ReadPos;
	/*根据传输位置和以发送的数量，释放空间*/
	DMA_CH7_Tx_ReadPos = 0;
}
/*第二种*/
void rb_write(void);
void rb_read(void);


int main(void)
{
	uint32_t i = 0;
	uint16_t len = 13;
	char* s = NULL;
	NVIC_Configuration();
	bsp_systick_init();
	bsp_led_init();
	bsp_uart1_init();
	bsp_uart2_init();
	while(1)
	{
		__NOP();
		start_uart1_dma();
		start_uart2_dma();
		if(system_ticks>=1000) {
			system_ticks = 0;
#if 1
			switch(i++) {
				case 0:
				case 1:
				case 2:
				case 3:
				case 4:
				case 5:
				case 6:
				case 7:
				case 8:
				case 9:
				case 10:
					len = 14;
#if 1
					s = (char* )mymalloc4(len);
					mymemcpy(s, "hello world4\r\n", len);
//#else
					s = (char* )mymalloc7(len);
					mymemcpy(s, "hello world7\r\n", len);
#endif
					GPIOC->ODR ^= GPIO_Pin_13;
					break;
				case 11:
					/*关闭一些外设，将系统的GPIO设置在STOP模式下需要的样子，如关闭LED灯*/
					bsp_system_save();
					EnterSleepMode_EXTI();
					/*设置唤醒源*/
					RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
//					RCC_ClockSecuritySystemCmd(ENABLE);//会导致NMI中断
					PWR_EnterSTOPMode(PWR_Regulator_LowPower, PWR_STOPEntry_WFI);
					ExitSleepMode_EXIT();
					ExitSleepMode_Sysclk();
					bsp_uart1_init();
					bsp_uart2_init();
					break;
				default:
#if 1
					len = 10;
					s = (char* )mymalloc4(len);
					mymemcpy(s, "wake up4\r\n", len);
					len = 14;
					s = (char* )mymalloc4(len);
					mymemcpy(s, "hello world4\r\n", len);
//#else
					len = 10;
					s = (char* )mymalloc7(len);
					mymemcpy(s, "wake up7\r\n", len);
					len = 14;
					s = (char* )mymalloc7(len);
					mymemcpy(s, "hello world7\r\n", len);
#endif
					GPIOC->ODR ^= GPIO_Pin_13;
					break;
			}
#endif
		}

	}
}


/**
  * @brief  Configures the nested vectored interrupt controller.
  * @param  None
  * @retval None
  */
void NVIC_Configuration(void)
{
	NVIC_InitTypeDef NVIC_InitStructure = {0};

	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
	
	NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel4_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);
	
	NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel7_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);
  /* Enable the EXTI9_5 Interrupt */
  NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
}




void bsp_systick_init(void)
{
	SysTick_Config(SystemCoreClock/1000);/*1ms*/

}

void SysTick_Handler(void)
{
	system_ticks++;
}


void bsp_led_init(void)
{

	GPIO_InitTypeDef GPIO_InitStruct = {0};
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
	
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_13;
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;
	GPIO_Init(GPIOC,&GPIO_InitStruct);
	
	/*默认灭*/
	GPIO_SetBits(GPIOC, GPIO_Pin_13);
//	GPIO_ResetBits(GPIOC, GPIO_Pin_13);
}

void bsp_uart2_init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure = {0};
	/*UART-GPIO init*/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
	/*TX----PA9*/
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	/*RX----PA10*/
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
//	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	/*UART init*/
	USART_InitTypeDef USART_InitStructure = {0};
	USART_InitStructure.USART_BaudRate = 115200;
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;
	USART_InitStructure.USART_StopBits = USART_StopBits_1;
	USART_InitStructure.USART_Parity = USART_Parity_No;
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
	USART_Init(USART2, &USART_InitStructure);
	
	/*使用DMA传输*/
	DMA_InitTypeDef DMA_InitStruct = {0};
	
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
  /* Initialize the DMA_PeripheralBaseAddr member */
  DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)(&(USART2->DR));
  /* Initialize the DMA_MemoryBaseAddr member */
  DMA_InitStruct.DMA_MemoryBaseAddr = 0;//不在这里设置值
  /* Initialize the DMA_DIR member */
  DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralDST;
  /* Initialize the DMA_BufferSize member */
  DMA_InitStruct.DMA_BufferSize = 0;
  /* Initialize the DMA_PeripheralInc member */
  DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  /* Initialize the DMA_MemoryInc member */
  DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;
  /* Initialize the DMA_PeripheralDataSize member */
  DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
  /* Initialize the DMA_MemoryDataSize member */
  DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
  /* Initialize the DMA_Mode member */
  DMA_InitStruct.DMA_Mode = DMA_Mode_Normal;
  /* Initialize the DMA_Priority member */
  DMA_InitStruct.DMA_Priority = DMA_Priority_Low;
  /* Initialize the DMA_M2M member */
  DMA_InitStruct.DMA_M2M = DMA_M2M_Disable;	
	

	DMA_Init(DMA1_Channel7, &DMA_InitStruct);
	/*interrupt config*/
//	USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
	USART_DMACmd(USART2, USART_DMAReq_Tx, ENABLE);
	/*启动*/
	USART_Cmd(USART2, ENABLE);

}

void bsp_uart1_init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure = {0};
	/*UART-GPIO init*/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1, ENABLE);

	/*TX----PA9*/
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	/*RX----PA10*/
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	/*UART init*/
	USART_InitTypeDef USART_InitStructure = {0};
	USART_InitStructure.USART_BaudRate = 115200;
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;
	USART_InitStructure.USART_StopBits = USART_StopBits_1;
	USART_InitStructure.USART_Parity = USART_Parity_No;
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
	USART_Init(USART1, &USART_InitStructure);
	
	/*使用DMA传输*/
	DMA_InitTypeDef DMA_InitStruct = {0};
	
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
  /* Initialize the DMA_PeripheralBaseAddr member */
  DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)(&(USART1->DR));
  /* Initialize the DMA_MemoryBaseAddr member */
  DMA_InitStruct.DMA_MemoryBaseAddr = 0;//不在这里设置值
  /* Initialize the DMA_DIR member */
  DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralDST;
  /* Initialize the DMA_BufferSize member */
  DMA_InitStruct.DMA_BufferSize = 0;
  /* Initialize the DMA_PeripheralInc member */
  DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  /* Initialize the DMA_MemoryInc member */
  DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;
  /* Initialize the DMA_PeripheralDataSize member */
  DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
  /* Initialize the DMA_MemoryDataSize member */
  DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
  /* Initialize the DMA_Mode member */
  DMA_InitStruct.DMA_Mode = DMA_Mode_Normal;
  /* Initialize the DMA_Priority member */
  DMA_InitStruct.DMA_Priority = DMA_Priority_Low;
  /* Initialize the DMA_M2M member */
  DMA_InitStruct.DMA_M2M = DMA_M2M_Disable;	
	

	DMA_Init(DMA1_Channel4, &DMA_InitStruct);
	/*interrupt config*/
//	USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
	USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);
	/*启动*/
	USART_Cmd(USART1, ENABLE);
}



/*
* 
*/
void USART1_IRQHandler(void)
{
	if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) {
		USART_ClearITPendingBit(USART1, USART_IT_RXNE);
	}
}

/*
* 
*/
void USART2_IRQHandler(void)
{
	if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET) {
		USART_ClearITPendingBit(USART2, USART_IT_RXNE);
	}
}
#if 0
/*
* 使用DMA发生串口数据，但是要异步发送，这需要动态分配+DMA传输，
* 这中间需要查表以多消息映射到单一DMA口。不查表行吗？可以，只要
* 当前节点可以得到下一个发送区域的地址和长度即可。为何malloc中
* 不见地址呢？因为malloc把地址作为了输出，即return的值是分配的内存地址。
* 但是DMA不一样，它需要把地址作为输入。即，malloc -- 对分配的内存做一些操作--
* DMA记录
*/
void put_dma_buffer(char *s, uint16_t len)
{
	uint8_t i = 0;
	/*查表写入数据——固定12个字节为一个区域，否则就需要动态分配算法*/
	/*动态分配算法中需要计算剩余空间，然后，把数据存于剩余空间内，再将当前地址
	更新，addr += wantedsize*/
	for(i = 0; i<TX_BUFFER_LENGTH; i++) {
		if(dma_tx_table[i].len == 0){
			dma_tx_table[i].dma_tx_addr = (uint32_t)s;
			dma_tx_table[i].len = len;
		}
	}
}

void start_uart_dma(void)
{
	uint8_t i = 0;	/*用于记录DMA发送的序号，确保每次调用可以切换发送的数据地址*/
	static uint8_t last_flag = TX_BUFFER_LENGTH;
	if((DMA1_Channel4->CCR & DMA_CCR1_EN) != 0) {
		/*查表*/
		for(i = last_flag+1; i!= last_flag; i++) {
			if(i>=TX_BUFFER_LENGTH) {
				i = 0;
			}
			/*查到有需要发送的数据*/
			if(dma_tx_table[i].len != 0){
				break;
			}
		}

		if(i != last_flag) {
			/*有数据可发*/
			DMA1_Channel4->CMAR = dma_tx_table[i].dma_tx_addr;//指定传输的地址，CMAR是32位寄存器，
			DMA_SetCurrDataCounter(DMA1_Channel4, dma_tx_table[i].len);
			DMA_ITConfig(DMA1_Channel4, DMA_IT_TC, ENABLE);
			DMA_Cmd(DMA1_Channel4, ENABLE);
		}
		else {
			/*无数据可发*/
			
		}
	}
	else {
		/*DMA 正在传输数据*/
	}
}
#endif
void DMA1_Channel4_IRQHandler(void)
{
	if(DMA_GetFlagStatus(DMA1_FLAG_TC4) == SET) {
		DMA_Cmd(DMA1_Channel4, DISABLE);	
		DMA_ITConfig(DMA1_Channel4, DMA_IT_TC, DISABLE);
		DMA_ClearFlag(DMA1_FLAG_TC4);
		dma_ch4_free(&uart1_tx_buffer[0]);
	}

}
void DMA1_Channel7_IRQHandler(void)
{
	if(DMA_GetFlagStatus(DMA1_FLAG_TC7) == SET) {
		DMA_Cmd(DMA1_Channel7, DISABLE);	
		DMA_ITConfig(DMA1_Channel7, DMA_IT_TC, DISABLE);
		DMA_ClearFlag(DMA1_FLAG_TC7);
		dma_ch7_free(&uart2_tx_buffer[0]);
	}

}

/*
* STOP模式下，所有时钟都停止了？那是如何知道有中断呢？
* 所有外设(GPIO是保持状态的，其它外设不清楚)保持退出前的状态
*/
void bsp_system_save(void)
{
	GPIO_InitTypeDef GPIO_InitStructure = {0};
	
	/*关闭UART外设——不然会有乱码*/
	DMA_DeInit(DMA1_Channel4);
	USART_DeInit(USART1);
	DMA_DeInit(DMA1_Channel7);
	USART_DeInit(USART2);
//	GPIO_DeInit(GPIOA);
	GPIO_SetBits(GPIOC, GPIO_Pin_13);
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO, ENABLE);
  /* Configure PB.09 as input floating */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  GPIO_Init(GPIOB, &GPIO_InitStructure);
	
  GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource9);
	
  /* ... and keep PB.09 configuration which will be used as EXTI Line9 source */
	GPIOB->CRH = 0x40;

}

void EnterSleepMode_EXTI(void)
{
  EXTI_InitTypeDef EXTI_InitStructure = {0};

	/* Configure the EXTI Line 9 */
  EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
  EXTI_InitStructure.EXTI_Line = EXTI_Line9;
  EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
  EXTI_InitStructure.EXTI_LineCmd = ENABLE;
  EXTI_Init(&EXTI_InitStructure);
}

void ExitSleepMode_EXIT(void)
{
  EXTI_InitTypeDef EXTI_InitStructure = {0};
	
	/* At this stage the system has resumed from STOP mode ************************/
  EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
  EXTI_InitStructure.EXTI_Line = EXTI_Line9;
  EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
  EXTI_InitStructure.EXTI_LineCmd = DISABLE;
  EXTI_Init(&EXTI_InitStructure);
}

void ExitSleepMode_Sysclk(void)
{
  ErrorStatus HSEStartUpStatus;

  /* Enable HSE */
  RCC_HSEConfig(RCC_HSE_ON);

  /* Wait till HSE is ready */
  HSEStartUpStatus = RCC_WaitForHSEStartUp();

  if(HSEStartUpStatus == SUCCESS)
  {
    /* Enable PLL */ 
    RCC_PLLCmd(ENABLE);

    /* Wait till PLL is ready */
    while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)
    {
    }

    /* Select PLL as system clock source */
    RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);

    /* Wait till PLL is used as system clock source */
    while(RCC_GetSYSCLKSource() != 0x08)
    {
    }
  }
}

/*******************************************************************************
* Function Name  : EXTI9_5_IRQHandler
* Description    : This function handles External lines 9 to 5 interrupt request.
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void EXTI9_5_IRQHandler(void)
{

  if(EXTI_GetITStatus(EXTI_Line9) != RESET)
  {
    /* Clear the EXTI Line 9 */  
    EXTI_ClearITPendingBit(EXTI_Line9);
  }
}


void uart1_putc(char c)
{
	uint8_t timeout = 0xFF;
	USART_SendData(USART1, c);
	do {
		timeout--;
		if(USART_GetFlagStatus(USART1, USART_FLAG_TC) == SET) {
			/*发送完毕*/
			break;
		}
	}while(timeout != 0);
	
}

int uart1_puts(char *s)
{
	int count = 0;
	while(*s != 0){
		count++;
		uart1_putc(*s);
		s++;
	}
	return count;
}


//RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
